/*
 * client.c
 *
 *  Created on: Oct 1, 2008
 *      Author: Doris, Steph
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>

//#define SERVER_PORT 5000
#define MAX_LINE 256
#define STDIN 0

int login(char username[], int s);
int list(int s);
int sendtxt(char username[], char message[], int s);
void logout(int s);
void quit(int s);

int main (int argc, char * argv[]) {
	FILE *fp;
	struct hostent *hp;
	struct sockaddr_in sin;
	char *host;
	char buf[MAX_LINE];
	int s;
	int nbytes; //for when accepting from the server
	int len;
	int server_port;

	if (argc == 3) {
		host = argv[1];
		server_port = atoi(argv[2]);
	}
	else {
		printf("Chat Client: Not enough arguments\n");
		fflush(stdout);
		exit(0);
	}

	/* translate host name into peer's IP address */
	hp = gethostbyname(host);
	if (!hp) {
		printf("Chat Client: unknown host: %s\n", host);
		fflush(stdout);
		exit(0);
	}

	/* builds address data structure */
	bzero((char *)&sin, sizeof(sin));
	sin.sin_family = AF_INET;
	//bcopy(hp->h_addr_list, (char *)&sin.sin_addr, hp->h_length);
	bcopy((char *)hp->h_addr, (char *)&sin.sin_addr.s_addr, hp->h_length);
	sin.sin_port = htons(server_port);

	/* active open */
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror ("socket");
		exit(0);
	}

	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
		perror("connect");
		close(s);
		exit(0);
	}

	//printf("Welcome to DS Chat Client!\nPlease use the following list of commands: login, list, sendto, logout, exit.\n");
	printf("Connected to server. Type exit to quit\n>");
	fflush(stdout);

	fd_set master;
	
	int k=0;
	
	while(1) {
//		if (k == 0) {
//			printf("Connected to server. Type exit to quit\n");
//			k++;	
//		}
		//printf("");
		FD_ZERO(&master);
		FD_SET(STDIN_FILENO, &master);	
		FD_SET(s, &master);
		int sel = select(s+1, &master, NULL, NULL, NULL);
		if(sel < 0) {
			perror ("Select");
			exit(0);
		}
		else if (sel > 0) {
				
			for(int c = 0; c < s+1; c++) { // checks each potential socket FD
				if (FD_ISSET(c, &master)) {
					if (c == s) { // response from server
						char recBuf[MAX_LINE];
						bzero(recBuf, MAX_LINE);
						recv(s, recBuf, MAX_LINE, 0);

						char msgType = recBuf[0];
						unsigned int numUsers = (recBuf[1]*10) + recBuf[2];
						char *users = recBuf+3;
						char userFrom[21];
						int tLen;
						switch (msgType) {
							case 0x02: //list msg
								//printf("num = %d\n", numUsers);
								while (numUsers > 0) {
									//printf("%d", numUsers);
									char nextUsers[21];
									strncpy(nextUsers, users, 20);
									nextUsers[20] = '\0';
									printf("%s\n", nextUsers);
									fflush(stdout);
									numUsers--;
									users += 20;
								}
								printf("<end list>\n>");
								fflush(stdout);
								//printf("%d", numUsers);
								break;
							case 0x05: // Response msg
								switch(recBuf[1]) {
									case 0x01: //success
										printf ("Success\n>");
										fflush(stdout);
										break;
									case 0x02: //malformed packet
										printf("malformed packet\n>");
										fflush(stdout);
										break;
									case 0x03: //failure
										printf("Failure\n>");
										fflush(stdout);
										break;
								}
								break;
							case 0x03: //sendTo msg
								strncpy (userFrom, recBuf+1, 20);
								userFrom[20] = '\0';
								printf("%s:",userFrom);
								fflush(stdout);
								tLen = (recBuf[21] << 8) + recBuf[22];
								for (int i = 0; i < tLen; i++) {
									printf("%c", recBuf[i+23]);
									fflush(stdout);
								}
								printf("\n");
								fflush(stdout);
							default:
								break;
						}
					}

					else if (c == STDIN_FILENO) {
						bzero(buf, MAX_LINE);
						if(fgets(buf, sizeof(buf), stdin) != NULL) {
							buf[strlen(buf) - 1] = '\0'; //gets rid of the \n at the end from fgets
							char *result = NULL;
							result = strtok(buf, " ");
							char *temp = NULL;
							if(result == NULL) {
								printf("Invalid command\n>");
								fflush(stdout);
							} else {
								if(strcmp(result, "list") == 0) {
									if(buf[strlen(buf)-1] != 't') {
										printf("Invalid command\n>");
										fflush(stdout);
									} else {
										list(s);
									}
								} else if(strcmp(result, "logout") == 0) {
									if(strlen(buf) != strlen("logout")) {
										printf("Invalid command\n>");
										fflush(stdout);
									} else {
										logout(s);
									}
								} else if(strcmp(result, "exit") == 0) {
									if(strlen(buf) != strlen("exit")) {
										printf("Invalid command\n>");
										fflush(stdout);
									} else {
										quit(s);
									}
								} else if(strcmp(result, "login") == 0) {
									result = strtok(NULL, " ");
									if(result == NULL) {
										printf("Bad username\n>");
										fflush(stdout);
									} else {
										login(buf+6, s);
									}
								} else if(strcmp(result, "sendto") == 0) {
									result = strtok(NULL, " ");
									char *txtmsg = NULL;
									if(result == NULL) {
										printf("Bad username\n>");
										fflush(stdout);
									} else {
										txtmsg = buf + strlen(result) + 8;
										if(txtmsg == NULL) {
											printf("Bad username\n>");
											fflush(stdout);
										} else {
											sendtxt(result, txtmsg, s);
										}
									}
								} else {
									printf("Invalid command\n>");
									fflush(stdout);
								}
							}
						}
					}				
				}// end if (FD_ISSET...)
			}// end for loop
		}// end first else
	} // end while
	return 1;
}// end main
/* LOGIN sends a login message to register with the server using the provided username.
 *
 * Rules:
 * Usernames are case sensitive.
 * Username cannot be more than 20 characters in length.
 * Username cannot contain any white space.
 *
 *
 * Return Values:
 * Returns "Success" if server can register username
 * Returns "Failure" if server cannot register username
 * Returns "Bad Username" if username does not fit requirements.
 *
 */
int login(char username[], int s) {
	int i = 0;
	int len = strlen(username);

	/* Rule: Can't have more than 20 chars in username */
	if  (len > 20) {
		printf("Username contains more than 20 characters.");
		fflush(stdout);
		return 0;
	}

	/* Rule: No whitespace (including space, tab, and newline)
	 * If less than 20 chars, pad with '\0' chars
	 */
	while (i < 20) {
		if (i < len) {
			if ((username[i] == ' ') ||
					(username[i] == '\t')||
					(username[i] == '\n')) {
				printf("Username contains whitespace.");
				fflush(stdout);
				return 0;
			}
		}
		else {
			username[i] = '\0';
		}
		i++;
	}

	/* All rules passed: send to server
	 * Msg Type (1B) = 0x01
	 * Username (20B) = username in parameter
	 */
	char msg[21];
	bzero(msg, 21);
	for (int temp = 0; temp < 21; temp++) {
		if (temp == 0)
			msg[0] = 0x01;
		else
			msg[temp] = username [temp - 1];
	}
	//printf("%s\n", msg);
	send (s, msg, 21, 0);
//	if (send (s, msg, 21, 0)) { //sent successful
//		//printf("sent\n");
//		char recBuf[MAX_LINE];
//		bzero(recBuf, MAX_LINE);
//		recv(s, recBuf, MAX_LINE, 0);
//		switch(recBuf[1]) {
//			case 0x01: // success
//				printf("Success!\n You are now registered and logged in as %s.\n", username);
//				break;
//			case 0x02: // malformed packet
//				printf("malformed packet\n");
//				break;
//			case 0x03:
//				printf("Failure.\n");
//				break;
//		}
	return 0;
}

/* SENDTXT sends a sendto message to the server to communicate with another client.
 *
 * Parameter:
 * The user name of the destination client
 * The text to send.
 *
 * Rules:
 * If either or both of the parameters are missing or if the username contains more than  20  characters,
 * "Bad username" should  be  printed  to  the console.
 * If  there  are  more  than  65535  characters  of  text,
 * "Bad message" should be printed to the console. *
 *
 */
int sendtxt(char username[], char message[], int s) {
	int i = 0;
	int userlen = strlen(username);

	if(userlen > 20) {
		printf("Username contains more than 20 characters.");
		fflush(stdout);
		return 0;
	}

	while(i < 20) {
		if(i < userlen) {
			if((username[i] == ' ') ||
					(username[i] == '\t') ||
					(username[i] == '\n')) {
				printf("Username contains white space.");
				fflush(stdout);
				return 0;
			}
		}
		i++;
	}

	/* Set up message to be sent to server */
	unsigned short tLen = strlen(message);
	char msg[23+tLen];
	int hitNull = 0;
	for(int temp = 0; temp < 21; temp++) {
		if(temp == 0) {
			msg[0] = 0x03;
		} else {
			if (hitNull)
				msg[temp] = '\0';
			else {
				if (username[temp-1] == '\0')
					hitNull = 1;
				msg[temp] = username[temp - 1];
			}
		}
	}

	msg[21] = (tLen & 0xFF00)>> 8;
	msg[22] = (tLen & 0x00FF);
//	int *txtlenp = strlen(message);
//	char *txtlencp = txtlenp;
//	msg[21] = txtlencp[2];
//	msg[22] = txtlencp[3];
	for (int i = 23, j = 0; i < 23+tLen; i++, j++){
		msg[i] = message[j];
	}
	send(s, msg, 23+tLen, 0);
//	if(send(s, msg, 23+tLen, 0)) { //sent successful
//		char recBuf[MAX_LINE];
//		bzero(recBuf, MAX_LINE);
//		recv(s, recBuf, MAX_LINE, 0);
//		switch(recBuf[1]) {
//			case 0x01: //success
//				break;
//			case 0x02: //malformed packet
//				printf ("malformed packet\n");
//				break;
//			case 0x03: //failure
//				printf ("Failure to send");
//				break;
//		}
//	}
	return 0;
//	unsigned short TLEN = strlen(message);
//									char msg[23+TLEN];
//									msg[0] = 0x03;
//									int i, size = 21;
//									for(i = 1; i < size && username[i-1] != '\0'; i++)
//										msg[i]=username[i-1];
//									for(; i < size; i ++)
//										msg[i] = '\0';
//									msg[21] = (TLEN >> 8) & 0xFF;
//									msg[22] = TLEN & 0xFF;
//									for(i = 23; i < 23+TLEN; i++)
//										msg[i]=message[i-23];
//									send(s, msg, 23+TLEN, 0);
}

/* LIST sends a list message requesting the list of users already logged in.
 *
 * Rules:
 * There should not be any extra parameters (other than "list" and specified socket).
 * The client should not close the connection with the server when executing this command.
 * After  executing  this  command,  the  client  should  still  be  able  to execute the list and login commands.
 */
int list(int s) {
	char msg[1];
	msg[0] = 0x02;
	//printf("listing\n");
	send(s, msg, 1, 0);
//	if (send (s, msg, 1, 0)) { // Sent Successfully
//		printf("Lists.\n");
//		char recBuf[MAX_LINE];
//		bzero(recBuf, MAX_LINE);
//		recv(s, recBuf, MAX_LINE, 0);
	return 0;
}

/* LOGOUT sends a logout message to the server.
 *
 * Rules:
 * There should not be any extra parameters (other than "logout" and specified socket).
 * The client should not close the connection with the server when executing this command.
 * After  executing  this  command,  the  client  should  still  be  able  to execute the list and login commands.
 */
void logout(int s) {
	char msg[1];
	msg[0] = 0x04;
	//send(s, msg, 1, 0);
	if (send (s, msg, 1, 0)) { //
		printf("Logged out successfully.\n");
		fflush(stdout);
	}
	else {
		printf("Could not log out user");
		fflush(stdout);
	}
}

/* QUIT closes the client socket and exits the program.
 *
 * Rules:
 * There should not be any extra parameters (other than "quit" and specified socket).
 */
void quit(int s) {
	close(s);
	//printf("Thank you for using DS Chat Client!\nGoodbye.");
	exit(1);
}

